using System;
using UnityEngine;
using UnityEngine.InputSystem;

/// <summary>
/// Several workable keys in the gameplay.
/// </summary>
public enum GameplayKeyCode
{
    S, A, D, W,
    DownArrow, LeftArrow, RightArrow, UpArrow,
    I, O, P, J, K, L,
    Z, X, C, V,
    NUM1, NUM2, NUM3, NUM4, NUM5, NUM6, NUM7, NUM8, NUM9, NUM0,
    Space, Enter, Escape,
    Shift, Ctrl, Alt,
    BackSpace,
    Tab,
    ENUM_END,
}

public class InputManager : SingletonMonoBehaviour<InputManager>, GameInput.IKeyboardActions
{
    private GameInput _gameInputActions;
    /// <summary>
    /// the phase of the key input
    /// </summary>
    private InputActionPhase[] _phaseList;
    private InputActionPhase[] PhaseList
    {
        get
        {
            if (_phaseList == null || _phaseList.Length == 0)
            {
                _phaseList = new InputActionPhase[(int)GameplayKeyCode.ENUM_END];//avoid null delegate
                for (int i = 0; i < _phaseList.Length; i++)
                {
                    _phaseList[i] = new InputActionPhase();
                }
            }
            return _phaseList;
        }
        set => _phaseList = value;
    }
    private Action[] _ON_Started;
    private Action[] ON_Started
    {
        get
        {
            if (_ON_Started == null || _ON_Started.Length == 0)
            {
                _ON_Started = new Action[(int)GameplayKeyCode.ENUM_END];
                for (int i = 0; i < _ON_Started.Length; i++)
                {
                    _ON_Started[i] = delegate { };
                }
            }
            else
            {
                for (int i = 0; i < _ON_Started.Length; i++)
                {
                    if (_ON_Started[i] == null)
                    {
                        _ON_Started[i] = delegate { };
                    }
                }
            }
            return _ON_Started;
        }
        set => _ON_Started = value;
    }
    private Action[] _ON_Performed;
    private Action[] ON_Performed
    {
        get
        {
            if (_ON_Performed == null || _ON_Performed.Length == 0)
            {
                _ON_Performed = new Action[(int)GameplayKeyCode.ENUM_END];
                for (int i = 0; i < _ON_Performed.Length; i++)
                {
                    _ON_Performed[i] = delegate { };
                }
            }
            else
            {
                for (int i = 0; i < _ON_Performed.Length; i++)
                {
                    if (_ON_Performed[i] == null) _ON_Performed[i] = delegate { };
                }
            }
            return _ON_Performed;
        }
        set => _ON_Performed = value;
    }
    private Action[] _ON_Canceled;
    private Action[] ON_Canceled
    {
        get
        {
            if (_ON_Canceled == null || _ON_Canceled.Length == 0)
            {
                _ON_Canceled = new Action[(int)GameplayKeyCode.ENUM_END];
                for (int i = 0; i < _ON_Canceled.Length; i++)
                {
                    _ON_Canceled[i] = delegate { };
                }
            }
            else
            {
                for (int i = 0; i < _ON_Canceled.Length; i++)
                {
                    if (_ON_Canceled[i] == null) _ON_Canceled[i] = delegate { };
                }
            }
            return _ON_Canceled;
        }
        set => _ON_Canceled = value;
    }
    private Vector2 _vector2Input;
    private InputActionPhase _inputAP_Vector2;
    private Action<Vector2> _ON_Vector2_Started;
    private Action<Vector2> ON_Vector2_Started
    {
        get
        {
            if (_ON_Vector2_Started == null) _ON_Vector2_Started = delegate (Vector2 vector2) { };
            return _ON_Vector2_Started;
        }
        set => _ON_Vector2_Started = value;
    }
    private Action<Vector2> _ON_Vector2_Performed;
    private Action<Vector2> ON_Vector2_Performed
    {
        get
        {
            if (_ON_Vector2_Performed == null) _ON_Vector2_Performed = delegate (Vector2 vector2) { };
            return _ON_Vector2_Performed;
        }
        set => _ON_Vector2_Performed = value;
    }
    private Action<Vector2> _ON_Vector2_Canceled;
    private Action<Vector2> ON_Vector2_Canceled
    {
        get
        {
            if (_ON_Vector2_Canceled == null) _ON_Vector2_Canceled = delegate (Vector2 vector2) { };
            return _ON_Vector2_Canceled;
        }
        set => _ON_Vector2_Canceled = value;
    }

    private void Awake()
    {
        INI_Singleton();
        //INI_InputEvent();
    }

    private void Start()
    {
        _gameInputActions = new GameInput();
        _gameInputActions.Keyboard.SetCallbacks(this);
        _gameInputActions.Keyboard.Enable();
    }

    private void Update()
    {
        PerformedEventHandler();
    }

    private void OnDisable()
    {
        UnregisterAllInputEvent();
    }

    /// <summary>
    /// Avoid null delegate.
    /// </summary>
    private void INI_InputEvent()
    {
        int length = (int)GameplayKeyCode.ENUM_END;
        _phaseList = new InputActionPhase[length];
        _ON_Started = new Action[length];
        _ON_Performed = new Action[length];
        _ON_Canceled = new Action[length];
        for (int i = 0; i < length; i++)
        {
            _phaseList[i] = new InputActionPhase();
            _ON_Started[i] = delegate { };
            _ON_Performed[i] = delegate { };
            _ON_Canceled[i] = delegate { };
        }
        _ON_Vector2_Started = delegate (Vector2 vector2) { };
        _ON_Vector2_Performed = delegate (Vector2 vector2) { };
        _ON_Vector2_Canceled = delegate (Vector2 vector2) { };
    }

    private void PerformedEventHandler()
    {
        for (int i = 0; i < (int)GameplayKeyCode.ENUM_END; i++)
        {
            if (PhaseList[i] == InputActionPhase.Performed) ON_Performed[i]();
        }
        if (_inputAP_Vector2 == InputActionPhase.Performed) ON_Vector2_Performed(_vector2Input);
    }
    private void EventHandler(GameplayKeyCode keyCode, InputActionPhase phase)
    {
        PhaseList[(int)keyCode] = phase;
        switch (phase)
        {
            case InputActionPhase.Started:
                ON_Started[(int)keyCode]();
                break;
            case InputActionPhase.Canceled:
                ON_Canceled[(int)keyCode]();
                break;
            default:
                break;
        }
    }
    private void EventHandler(Vector2 input, InputActionPhase phase)
    {
        _vector2Input = input;
        _inputAP_Vector2 = phase;
        switch (phase)
        {
            case InputActionPhase.Started:
                ON_Vector2_Started(_vector2Input);
                break;
            case InputActionPhase.Canceled:
                ON_Vector2_Canceled(_vector2Input);
                break;
            default:
                break;
        }
    }
    public void Reg_InputEvent(GameplayKeyCode keyCode, InputActionPhase phase, Action action)
    {
        switch (phase)
        {
            case InputActionPhase.Started:
                ON_Started[(int)keyCode] += action;
                break;
            case InputActionPhase.Performed:
                ON_Performed[(int)keyCode] += action;
                break;
            case InputActionPhase.Canceled:
                ON_Canceled[(int)keyCode] += action;
                break;
            default:
                break;
        }
    }
    public void Reg_InputEvent(InputActionPhase phase, Action<Vector2> action)
    {
        switch (phase)
        {
            case InputActionPhase.Started:
                ON_Vector2_Started += action;
                break;
            case InputActionPhase.Performed:
                ON_Vector2_Performed += action;
                break;
            case InputActionPhase.Canceled:
                ON_Vector2_Canceled += action;
                break;
            default:
                break;
        }
    }
    public void UnregisterInputEvent(GameplayKeyCode keyCode, InputActionPhase phase, Action action)
    {
        switch (phase)
        {
            case InputActionPhase.Started:
                ON_Started[(int)keyCode] -= action;
                break;
            case InputActionPhase.Performed:
                ON_Performed[(int)keyCode] -= action;
                break;
            case InputActionPhase.Canceled:
                ON_Canceled[(int)keyCode] -= action;
                break;
            default:
                break;
        }
    }
    public void UnregisterInputEvent(InputActionPhase phase, Action<Vector2> action)
    {
        switch (phase)
        {
            case InputActionPhase.Started:
                ON_Vector2_Started -= action;
                break;
            case InputActionPhase.Performed:
                ON_Vector2_Performed -= action;
                break;
            case InputActionPhase.Canceled:
                ON_Vector2_Canceled -= action;
                break;
            default:
                break;
        }
    }
    private void UnregisterAllInputEvent()
    {
        for (int i = 0; i < (int)GameplayKeyCode.ENUM_END; i++)
        {
            Delegate[] started = ON_Started[i].GetInvocationList();
            for (int j = 0; j < started.Length; j++)
            {
                ON_Started[i] -= (Action)started[j];
            }
            Delegate[] performed = ON_Started[i].GetInvocationList();
            for (int j = 0; j < performed.Length; j++)
            {
                ON_Started[i] -= (Action)performed[j];
            }
            Delegate[] canceled = ON_Started[i].GetInvocationList();
            for (int j = 0; j < canceled.Length; j++)
            {
                ON_Started[i] -= (Action)canceled[j];
            }
        }
        Delegate[] vector2Started = ON_Vector2_Started.GetInvocationList();
        for (int j = 0; j < vector2Started.Length; j++)
        {
            ON_Vector2_Started -= (Action<Vector2>)vector2Started[j];
        }
        Delegate[] vector2Performed = ON_Vector2_Performed.GetInvocationList();
        for (int j = 0; j < vector2Performed.Length; j++)
        {
            ON_Vector2_Performed -= (Action<Vector2>)vector2Performed[j];
        }
        Delegate[] vector2Canceled = ON_Vector2_Canceled.GetInvocationList();
        for (int j = 0; j < vector2Canceled.Length; j++)
        {
            ON_Vector2_Canceled -= (Action<Vector2>)vector2Canceled[j];
        }
    }

    #region KeyboardInputEvent
    void GameInput.IKeyboardActions.OnK1_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.S, context.phase); }
    void GameInput.IKeyboardActions.OnK1_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.A, context.phase); }
    void GameInput.IKeyboardActions.OnK1_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.D, context.phase); }
    void GameInput.IKeyboardActions.OnK1_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.W, context.phase); }
    void GameInput.IKeyboardActions.OnK2_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.DownArrow, context.phase); }
    void GameInput.IKeyboardActions.OnK2_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.LeftArrow, context.phase); }
    void GameInput.IKeyboardActions.OnK2_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.RightArrow, context.phase); }
    void GameInput.IKeyboardActions.OnK2_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.UpArrow, context.phase); }
    void GameInput.IKeyboardActions.OnK3_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.I, context.phase); }
    void GameInput.IKeyboardActions.OnK3_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.O, context.phase); }
    void GameInput.IKeyboardActions.OnK3_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.P, context.phase); }
    void GameInput.IKeyboardActions.OnK3_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.J, context.phase); }
    void GameInput.IKeyboardActions.OnK3_5(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.K, context.phase); }
    void GameInput.IKeyboardActions.OnK3_6(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.L, context.phase); }
    void GameInput.IKeyboardActions.OnK4_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Z, context.phase); }
    void GameInput.IKeyboardActions.OnK4_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.X, context.phase); }
    void GameInput.IKeyboardActions.OnK4_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.C, context.phase); }
    void GameInput.IKeyboardActions.OnK4_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.V, context.phase); }
    void GameInput.IKeyboardActions.OnK5_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM1, context.phase); }
    void GameInput.IKeyboardActions.OnK5_10(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM0, context.phase); }
    void GameInput.IKeyboardActions.OnK5_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM2, context.phase); }
    void GameInput.IKeyboardActions.OnK5_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM3, context.phase); }
    void GameInput.IKeyboardActions.OnK5_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM4, context.phase); }
    void GameInput.IKeyboardActions.OnK5_5(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM5, context.phase); }
    void GameInput.IKeyboardActions.OnK5_6(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM6, context.phase); }
    void GameInput.IKeyboardActions.OnK5_7(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM7, context.phase); }
    void GameInput.IKeyboardActions.OnK5_8(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM8, context.phase); }
    void GameInput.IKeyboardActions.OnK5_9(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM9, context.phase); }
    void GameInput.IKeyboardActions.OnK6_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Space, context.phase); }
    void GameInput.IKeyboardActions.OnK6_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Enter, context.phase); }
    void GameInput.IKeyboardActions.OnK6_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Escape, context.phase); }
    void GameInput.IKeyboardActions.OnK6_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Shift, context.phase); }
    void GameInput.IKeyboardActions.OnK6_5(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Ctrl, context.phase); }
    void GameInput.IKeyboardActions.OnK6_6(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Alt, context.phase); }
    void GameInput.IKeyboardActions.OnK6_7(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.BackSpace, context.phase); }
    void GameInput.IKeyboardActions.OnK6_8(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Tab, context.phase); }
    void GameInput.IKeyboardActions.OnK_Dir(InputAction.CallbackContext context) { EventHandler(context.ReadValue<Vector2>(), context.phase); }
    #endregion
}
